/*=========================================================================================================================UNION=======================*/ %union { char* str; long double number; } /*=========================================================================================================================TOKENS======================*/ %token SIN COS TG ARCSIN ARCCOS ARCTG %token SH CH CTH EXP LN LOG %token ROUND MAX MIN RAND ABS %token '(' ')' '-' '+' '*' '/' '%' '^' ',' %token PI E CONSTANT /*=========================================================================================================================TYPES=======================*/ %type constants %type cast_expression %type max_func_expression %type min_func_expression %type functions %type unary_operator_and_function %type multiplicative_expression %type additive_expression /*=========================================================================================================================START=DECLARATION===========*/ %start translation_unit %{ /*=======================================================================SYSTEM=SETTINGS===============*/ /* For compilation using C++ */ extern "C" { int yyparse(void); int yylex(void); int yywrap(void); void yyerror(const char *); } /*=======================================================================LEX=YACC=SETTINGS=============*/ extern char yytext[]; #define YYDEBUG_LEXER_TEXT yytext /*=======================================================================PROGRAM=SETTINGS==============*/ #include #include #include #include using std::cout; using std::fetestexcept; #define _USE_MATH_DEFINES #include #include long double _result; %} %{ /*=======================================================================================================================================================================================================*/ /*=======================================================================================================================================================================================================*/ /*=======================================================================================================================================================================================================*/ %} %% /*=========================================================================================================================C=GRAMMAR===================*/ constants : PI { $$ = M_PI; } | E { $$ = M_E; } | CONSTANT { int ret = sscanf ($1, "%Lf", &($$)); if (errno == EILSEQ) throw "Translating constant error. \nInput byte sequence does not form a valid character."; if (errno == EINTR ) throw "Translating constant error. \nThe read operation was interrupted by a signal."; if (errno == EINVAL) throw "Translating constant error. \nNot enough arguments; or format is NULL."; if (errno == ENOMEM) throw "Translating constant error. \nOut of memory."; if (errno == ERANGE) throw "Translating constant error. \nThe result of an integer conversion would exceed the size that can be stored in the corresponding integer type."; if (ret == EOF) throw "Translating constant error. \nThe end of input is reached before successful conversion or matching failure occured. Read error occured"; if (ret == 0) throw "Translating constant error. \nThe number cann't been read"; } ; cast_expression : '(' additive_expression ')' { $$ = $2; } | constants { $$ = $1; } ; max_func_expression : max_func_expression ',' additive_expression { /*value of $$ will be max between $1 and $3 */ if (($1) > ($3)) $$ = $1; else $$ = $3; } | additive_expression { $$ = $1; } ; min_func_expression : min_func_expression ',' additive_expression { /*value of $$ will be min between $1 and $3 */ if (($1) > ($3)) $$ = $3; else $$ = $1; } | additive_expression { $$ = $1; } ; functions : cast_expression | MAX '(' max_func_expression ')' { $$ = $3; } | MIN '(' min_func_expression ')' { $$ = $3; } | SIN '(' additive_expression ')' { $$ = sinl ($3); if (errno == EDOM) throw "Error in taking sin. \nArgument is infinity."; if (fetestexcept (FE_INVALID)) throw "Error in taking sin. \n"; if (isnan ($$)) throw "Error in taking sin. \nResult is not a number."; } | COS '(' additive_expression ')' { $$ = cosl ($3); if (errno == EDOM) throw "Error in taking cos. \nArgument is infinity."; if (fetestexcept (FE_INVALID)) throw "Error in taking cos. \n"; if (isnan ($$)) throw "Error in taking sin. \nResult is not a number."; } | TG '(' additive_expression ')' { $$ = tanl ($3); if ($$ == HUGE_VALL || $$ == -HUGE_VALL) throw "Error in taking tg. \nOverflow."; if (errno == EDOM) throw "Error in taking tg. \nArgument is infinity."; if (fetestexcept (FE_INVALID) || fetestexcept (FE_OVERFLOW)) throw "Error in taking tg. \n"; if (isnan ($$)) throw "Error in taking sin. \nResult is not a number."; } | ARCSIN '(' additive_expression ')' { $$ = asinl ($3); if (errno == EDOM || fetestexcept (FE_INVALID)) throw "Error in taking arcsin. \nArgument is outside the range."; if (isnan ($$)) throw "Error in taking sin. \nResult is not a number."; } | ARCCOS '(' additive_expression ')' { $$ = acosl ($3); if (errno == EDOM || fetestexcept (FE_INVALID)) throw "Error in taking arccos. \nArgument is outside the range."; if (isnan ($$)) throw "Error in taking sin. \nResult is not a number."; } | ARCTG '(' additive_expression ')' { $$ = atanl ($3); if (isnan ($$)) throw "Error in taking arctg. \nResult is not a number."; } | SH '(' additive_expression ')' { $$ = sinhl ($3); if ($$ == HUGE_VALL || $$ == -HUGE_VALL) throw "Error in taking hyperbolic sin. \nOverflow."; if (errno == ERANGE || fetestexcept (FE_OVERFLOW)) throw "Error in taking hyperbolic sin. \nArgument is outside the range."; if (isnan ($$)) throw "Error in taking sin. \nResult is not a number."; } | CH '(' additive_expression ')' { $$ = coshl ($3); if ($$ == HUGE_VALL || $$ == -HUGE_VALL) throw "Error in taking hyperbolic cos. \nOverflow."; if (errno == ERANGE || fetestexcept (FE_OVERFLOW)) throw "Error in taking hyperbolic cos. \nArgument is outside the range."; if (isnan ($$)) throw "Error in taking sin. \nResult is not a number."; } | CTH '(' additive_expression ')' { $$ = tanhl ($3); if (isnan ($$)) throw "Error in taking hyperbolic tg. \nResult is not a number."; } | EXP '(' additive_expression ')' { $$ = expl ($3); if ($$ == HUGE_VALL || $$ == -HUGE_VALL) throw "Error in taking exp. \nOverflow."; if (errno == ERANGE || fetestexcept (FE_OVERFLOW) || fetestexcept (FE_UNDERFLOW)) throw "Error in taking exp. \nArgument is outside the range."; if (isnan ($$)) throw "Error in taking sin. \nResult is not a number."; } | LN '(' additive_expression ')' { $$ = logl ($3); if ($$ == HUGE_VALL || $$ == -HUGE_VALL) throw "Error in taking ln. \nOverflow."; if (errno == EDOM || fetestexcept (FE_INVALID)) throw "Error in taking ln. \nArgument is negative."; if (errno == ERANGE || fetestexcept (FE_DIVBYZERO)) throw "Error in taking ln. \nArgument is equal to zero."; if (isnan ($$)) throw "Error in taking sin. \nResult is not a number."; } | LOG '(' additive_expression ',' additive_expression ')' { long double div1 = logl ($5); if (div1 == HUGE_VALL || div1 == -HUGE_VALL) throw "Error in taking log. \nOverflow."; if (errno == EDOM || fetestexcept (FE_INVALID)) throw "Error in taking log. \nArgument is negative."; if (errno == ERANGE || fetestexcept (FE_DIVBYZERO)) throw "Error in taking log. \nArgument is equal to zero."; if (isnan (div1)) throw "Error in taking log. \nResult is not a number."; long double div2 = logl ($3); if (div2 == HUGE_VALL || div2 == -HUGE_VALL) throw "Error in taking log. \nOverflow."; if (errno == EDOM || fetestexcept (FE_INVALID)) throw "Error in taking log. \nBase is negative."; if (errno == ERANGE || fetestexcept (FE_DIVBYZERO)) throw "Error in taking log. \nBase is equal to zero."; if (isnan (div2)) throw "Error in taking log. \nBase is not a number."; if (div2 == 0.0) throw "Error in taking log. \nBase is equal to one."; $$ = div1 / div2; if (isnan ($$)) throw "Error in taking log. \nSomething is not a number."; } | ROUND '(' additive_expression ')' { $$ = roundl ($3); } | RAND '(' additive_expression ')' { $$ = static_cast ( random () % ( static_cast (round($3)) ) ); } | ABS '(' additive_expression ')' { if (($3) > 0) $$ = $3; else $$ = 0 - ($3); } ; unary_operator_and_function : '+' functions { $$ = $2; } | '-' functions { $$ = - ($2); } ; multiplicative_expression : functions { $$ = $1; } | unary_operator_and_function { $$ = $1; } | multiplicative_expression '*' functions { $$ = $1 * $3; } | multiplicative_expression '/' functions { if (($3) == 0.0) throw "Error in dividing. \nDivisor is equal to zero."; $$ = $1 / $3; } | multiplicative_expression '%' functions { if (static_cast (round($3)) == 0.0) throw "Error in taking remainder after dividing. \nDivisor is equal to zero."; $$ = static_cast ( static_cast (round($1)) % static_cast (round($3)) ); } | multiplicative_expression '^' functions { $$ = powl ($1, $3); if ($$ == HUGE_VALL || $$ == -HUGE_VALL) throw "Error in taking pow. \nOverflow."; if (errno == EDOM || fetestexcept (FE_INVALID)) throw "Error in taking pow. \nFirst argument is negative, and second argument is a finite noninteger."; if (errno == ERANGE || fetestexcept (FE_DIVBYZERO)) throw "Error in taking pow. \nFirst argument is zero, and second argument is negative."; if (errno == ERANGE || fetestexcept (FE_OVERFLOW)) throw "Error in taking pow. \nThe result overflows."; if (errno == ERANGE || fetestexcept (FE_UNDERFLOW)) throw "Error in taking pow. \nThe result underflows."; if (isnan ($$)) throw "Error in taking pow. \nResult is not a number."; } ; additive_expression :multiplicative_expression { $$ = $1; } | additive_expression '+' multiplicative_expression { $$ = $1 + $3; } | additive_expression '-' multiplicative_expression { $$ = $1 - $3; } ; translation_unit : additive_expression { _result = $1; } ; /*=========================================================================================================================C++=FUNCTIONS===============*/ %%/*=====================================================================================================================================================================================================*/ /*=======================================================================================================================================================================================================*/ /*=======================================================================================================================================================================================================*/ /*=======================================================================LEX=YACC=FUNCTIONS============*/ /*========================================================YYERROR===============*/ void yyerror(const char *s) { fflush(stdout); fprintf(stderr, "\n*** %s\n", s); } /*========================================================MAIN===================*/ int main() { yydebug = 0; /* 1 - for debugging mode */ srandom (time (NULL)); try { yyparse(); cout << "\nresult = " /*<< _result << "\n"*/; printf ("%Lf\n", (_result)); } catch (const char* matherr) { cout << "\nFatal error:\n" << matherr << "\n"; } catch (...) { cout << "Unexpected exception!!! Wrong input.\n"; } return 0; } /*=======================================================================PROGRAM=FUNCTIONS=============*/